#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>

#include <unistd.h>
#include <sys/wait.h>
#define BUFF_SIZE 128
#define ARGV_SIZE 128
#define CWD_SIZE 128
#define DELIM " "
std::string GetHostName()
{
    char hostname[BUFF_SIZE] = {0};
    gethostname(hostname, BUFF_SIZE);
    return hostname;
}
std::string GetLoginName()
{
    return getlogin();
}
std::string GetCwd()
{
    char buffer[CWD_SIZE];
    return getcwd(buffer, CWD_SIZE);
}
std::string MakeCommandLinePrompt()
{
    // std::string command_line_prompt;
    // command_line_prompt = command_line_prompt + GetLoginName() + "@" + GetHostName() + "$ ";
    return GetLoginName() + "@" + GetHostName() + ":" + GetCwd() + "$ ";
}
void ParseCommand(const std::string &command_line, char *argv[])
{
    int i = 0;
    argv[i++] = strtok((char *)command_line.c_str(), DELIM);
    while (argv[i++] = strtok(nullptr, DELIM))
        ;
}
void ExcuteCommand(char *argv[])
{
    pid_t id = fork();
    if (id == 0)
    {
        // child
        execvp(argv[0], argv);
        perror("execvp");
    }
    int status = 0;
    pid_t rid = waitpid(id, &status, 0);
    if (rid > 0)
    {
        if (!WIFEXITED(status))
        {
            printf("command excute error, exit_code:%d->%s\n", WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
        }
        // else
        // {
        //     printf("command excute success, exit_code:%d\n", WEXITSTATUS(status));
        // }
    }
    else
    {
        perror("waitpid");
        exit(1);
    }
}
void Cd(const char* path)
{
    std::string oldpwd = getenv("PWD"), newpwd = getenv("OLDPWD");
    chdir(path);
    oldpwd = "OLDPWD=" + oldpwd;
    newpwd = "PWD=" + newpwd;

    putenv((char *)oldpwd.c_str());
    putenv((char *)newpwd.c_str());
}
bool CheckBuildInCommand(char *argv[])
{
    if (strcmp(argv[0], "cd") == 0)
    {
        char *path = argv[1];
        if (path == nullptr || strcmp(path, "~") == 0)
        {
            Cd(getenv("HOME"));
        }
        else if (strcmp(path, "-") == 0)
        {
            
            Cd(getenv("OLDPWD"));
        }
        else
        {
            Cd(path);
        }
        return true;
    }
    return false;
}
int main()
{

    while (true)
    {
        // 0. make命令行提示符
        std::string command_line_prompt = MakeCommandLinePrompt();
        std::cout << command_line_prompt;
        // 1. 获取用户输入的命令
        std::string command_line;
        std::getline(std::cin, command_line);
        // 2. 解析命令行
        char *argv[ARGV_SIZE] = {0};
        ParseCommand(command_line, argv);
        // for (int i = 0; argv[i]; i++)
        // {
        //     printf("argv[%d]-> %s\n", i, argv[i]);
        // }
        // 检查是否是内建命令
        if (!CheckBuildInCommand(argv))
        { // 3. 建立一个子进程（fork）
            // 4. 替换子进程（execvp）
            // 5. 父进程等待子进程退出（wait）
            ExcuteCommand(argv);
        }
    }

    return 0;
}